﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO.Ports;
using System.Threading;
using System.Windows.Threading;
using System.Data;
using System.IO;

namespace GroundStation
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        SerialPort ioPort = new SerialPort("com3", 9600, Parity.None, 8);
        private List<PlaneValues> Valuelist = new List<PlaneValues>();
        private delegate void UpdateUiTextDelegate(string text);
        private int csvIndex = 0;
        private string csvBuff = "";
        private int lastCsvPos = 0;
        private string cNewLine = Char.ConvertFromUtf32(10);
        private string MsgType = "";
        private List<string> Clist = new List<string>();
        StreamWriter logFile;


        public MainWindow()
        {
            InitializeComponent();
        }


        public void StartRecv()
        {
            bool firstLoop = true;
            ioPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
            ioPort.Open();
            logFile = File.AppendText(DateTime.Now.ToString("yyyy-MM-dd_hh-mm-ss") + ".csv");

            foreach(PlaneValues pList in Valuelist)
            {
                if (firstLoop)
                    firstLoop = false;
                else
                    logFile.Write("; ");

                logFile.Write(pList.Name + "/" + pList.Unit);
            }
        }

        private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
        {
            int revLen = ioPort.BytesToRead;

            if (revLen > 0)
            {
                byte[] buff = new byte[revLen];

                ioPort.Read(buff, 0, revLen);
                Dispatcher.Invoke(DispatcherPriority.Send, new UpdateUiTextDelegate(Updating), UnicodeEncoding.UTF8.GetString(buff));
            }
        }

        private void Updating(string text)
        {
            csvBuff += text;
            //ConsoleOut.Text += text;
            //ConsoleOut.ScrollToEnd();

            for (int i = 0; i < csvBuff.Length; i++)
            {
                if (csvBuff.Substring(i, 1) == ";")
                {
                    RefreshValue(csvIndex, csvBuff.Substring(lastCsvPos, i - lastCsvPos));

                    lastCsvPos = i + 1;
                    csvIndex++;
                }
                if (csvBuff.Substring(i, 1) == cNewLine)
                {
                    RefreshValue(csvIndex, csvBuff.Substring(lastCsvPos, i - lastCsvPos - 1));

                    lastCsvPos = i + 1;
                    csvIndex = 0;
                }
            }

            if (lastCsvPos <= csvBuff.Length)
            {
                csvBuff = csvBuff.Substring(lastCsvPos);
            }
            else
            {
                csvBuff = "";
            }
            lastCsvPos = 0;
        }

        private void RefreshValue(int Index, string Value)
        {
            int i;
            string effValue = Value;

            if (Index == 0)
            {
                i = Value.IndexOf(' ');
                if (i > 0)
                {
                    MsgType = Value.Substring(0, i);
                    effValue = Value.Substring(i + 1);
                }
                else
                {
                    MsgType = Value;
                }
            }

            if (MsgType == "STATE")
            {
                if (Index == 0)
                    logFile.Write("\r\n" + Value.Substring(7));
                else
                    logFile.Write("; " + Value.Replace('.', ','));

                foreach (PlaneValues pVal in Valuelist)
                {
                    if (pVal.SrcPosition == Index) pVal.Value = effValue;
                }
            }

            if (MsgType == "CMD")
            {
                ConsoleOut.Text += Value + "\n\r";
                ConsoleOut.ScrollToEnd();
            }
        }

        private void FillComList()
        {
            Clist.Add("PitchCtrP");
            Clist.Add("PitchCtrI");
            Clist.Add("RollCtrP");
            Clist.Add("RollCtrI");
            Clist.Add("YawCtrP");
            Clist.Add("YawCtrI");
            Clist.Add("DisableServos");
            Clist.Add("FireParachute");
            Clist.Add("ReleseBalloon");
            Clist.Add("RadioFrequency");
            Clist.Add("UseStatusChannel");
            Clist.Add("DestLatitude");
            Clist.Add("DestLongitude");
            Clist.Add("TargetAirSpeed");
            Clist.Add("CalibrationMode");
            Clist.Sort();
        }


        private void CreateList()
        {
            Valuelist.Add(new PlaneValues(StackPannel1, "Time", "", PlaneValues.ValueType.Text, 0));
            Valuelist.Add(new PlaneValues(StackPannel1, "Latitude", "°", PlaneValues.ValueType.Number, 1));
            Valuelist.Add(new PlaneValues(StackPannel1, "Longitude", "°", PlaneValues.ValueType.Number, 2));
            Valuelist.Add(new PlaneValues(StackPannel1, "Altitude", "m", PlaneValues.ValueType.Number, 3));
            Valuelist.Add(new PlaneValues(StackPannel1, "GPS Speed", "m/s", PlaneValues.ValueType.Number, 4));
            Valuelist.Add(new PlaneValues(StackPannel1, "Yaw", "°", PlaneValues.ValueType.Number, 5, - 180, 180));
            Valuelist.Add(new PlaneValues(StackPannel1, "Roll", "°", PlaneValues.ValueType.Number, 6, -45 , 45));
            Valuelist.Add(new PlaneValues(StackPannel1, "Pitch", "°", PlaneValues.ValueType.Number, 7, -45, 45));
            Valuelist.Add(new PlaneValues(StackPannel1, "Air Speed", "m/s", PlaneValues.ValueType.Number, 8, 0, 30));
            Valuelist.Add(new PlaneValues(StackPannel1, "Voltage", "V", PlaneValues.ValueType.Number, 9, 3, 4.2));
            Valuelist.Add(new PlaneValues(StackPannel1, "Current", "A", PlaneValues.ValueType.Number, 10, 0, 1.5));
            Valuelist.Add(new PlaneValues(StackPannel1, "Energy", "J", PlaneValues.ValueType.Number, 11, 57600, 0));
            Valuelist.Add(new PlaneValues(StackPannel1, "Barometer Temperature", "°C", PlaneValues.ValueType.Number, 12));
            Valuelist.Add(new PlaneValues(StackPannel1, "Barometric Pressure", "hPa", PlaneValues.ValueType.Number, 13));
            Valuelist.Add(new PlaneValues(StackPannel1, "Outer Temperature", "°C", PlaneValues.ValueType.Number, 14));
            Valuelist.Add(new PlaneValues(StackPannel1, "Inner Temperature", "°C", PlaneValues.ValueType.Number, 15));
            Valuelist.Add(new PlaneValues(StackPannel1, "Left servo position", "°", PlaneValues.ValueType.Number, 16, -45, 45));
            Valuelist.Add(new PlaneValues(StackPannel1, "Right servo position", "°", PlaneValues.ValueType.Number, 17, -45, 45));
            Valuelist.Add(new PlaneValues(StackPannel1, "Target heading", "°", PlaneValues.ValueType.Number, 18, -180, 180));
            Valuelist.Add(new PlaneValues(StackPannel1, "Distance", "m", PlaneValues.ValueType.Number, 19));
            Valuelist.Add(new PlaneValues(StackPannel1, "Horizontal dilution", "m", PlaneValues.ValueType.Number, 20));
            Valuelist.Add(new PlaneValues(StackPannel1, "GPS fix", "", PlaneValues.ValueType.Boolean, 21));
            Valuelist.Add(new PlaneValues(StackPannel1, "RSSI", "", PlaneValues.ValueType.Number, 22));
            Valuelist.Add(new PlaneValues(StackPannel1, "LostPackets", "", PlaneValues.ValueType.Number, 23));
            Valuelist.Add(new PlaneValues(StackPannel1, "Magnetic field", "", PlaneValues.ValueType.Number, 24));
        }

        private void WindowLoadedEvent(object sender, RoutedEventArgs e)
        {
            FillComList();
            CreateList();
            ConsoleIn.Focus();
            StartRecv();
        }

        private void ConsoleIn_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (ConsoleIn.Text.Length > 0)
            {
                CommandList.Items.Clear();
                CommandList.Visibility = System.Windows.Visibility.Visible;
                foreach (string ltext in Clist)
                {
                    if (ltext.IndexOf(ConsoleIn.Text, StringComparison.OrdinalIgnoreCase) > -1)
                    {
                        CommandList.Items.Add(ltext);
                    }
                }
                CommandList.SelectedIndex = 0;
            }
            else
            {
                CommandList.Visibility = System.Windows.Visibility.Collapsed;
            }
        }

        private void ConsoleIn_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                e.Handled = true;
                ioPort.Write(ConsoleIn.Text + "\r\n");
                HistList.Items.Add(ConsoleIn.Text);
                ConsoleIn.Text = "";
            }
        }

        private void HistList_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                e.Handled = true;
                HistList.Visibility = System.Windows.Visibility.Collapsed;
                ConsoleIn.Text = (string)HistList.Items[HistList.SelectedIndex];
                ConsoleIn.SelectionStart = ConsoleIn.Text.Length;
                ConsoleIn.Focus();
            }
            else if (e.Key == Key.Escape)
            {
                e.Handled = true;
                HistList.Visibility = System.Windows.Visibility.Collapsed;
                ConsoleIn.Focus();
            }
        }

        private void ConsoleIn_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Up)
            {
                e.Handled = true;
                HistList.Visibility = System.Windows.Visibility.Visible;
                if (CommandList.Visibility == System.Windows.Visibility.Visible && CommandList.SelectedIndex > 0) CommandList.SelectedIndex--;
                if (HistList.Visibility == System.Windows.Visibility.Visible && HistList.SelectedIndex > 0) HistList.SelectedIndex--;
            }
            if (e.Key == Key.Down)
            {
                e.Handled = true;
                if (CommandList.Visibility == System.Windows.Visibility.Visible && CommandList.SelectedIndex < CommandList.Items.Count) CommandList.SelectedIndex++;
                if (HistList.Visibility == System.Windows.Visibility.Visible && HistList.SelectedIndex < HistList.Items.Count) HistList.SelectedIndex++;
            }

            if (e.Key == Key.Tab)
            {
                e.Handled = true;
                if (CommandList.Visibility == System.Windows.Visibility.Visible && CommandList.SelectedIndex > -1) ConsoleIn.Text = (string)CommandList.Items[CommandList.SelectedIndex];
                if (HistList.Visibility == System.Windows.Visibility.Visible && HistList.SelectedIndex > -1) ConsoleIn.Text = (string)HistList.Items[HistList.SelectedIndex];
                CommandList.Visibility = System.Windows.Visibility.Collapsed;
                HistList.Visibility = System.Windows.Visibility.Collapsed;
                ConsoleIn.SelectionStart = ConsoleIn.Text.Length;
            }
        }

        private void HistList_LostFocus(object sender, RoutedEventArgs e)
        {
            //HistList.Visibility = System.Windows.Visibility.Collapsed;
        }

        private void HistList_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            ConsoleIn.Text = (string)HistList.Items[HistList.SelectedIndex];
            HistList.Visibility = System.Windows.Visibility.Collapsed;
            ConsoleIn.Focus();
        }

        private void CommandList_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            ConsoleIn.Text = (string)CommandList.Items[CommandList.SelectedIndex];
            CommandList.Visibility = System.Windows.Visibility.Collapsed;
            ConsoleIn.Focus();
        }

        private void CommandList_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                e.Handled = true;
                CommandList.Visibility = System.Windows.Visibility.Collapsed;
                ConsoleIn.Text = (string)CommandList.Items[CommandList.SelectedIndex];
                ConsoleIn.SelectionStart = ConsoleIn.Text.Length;
                ConsoleIn.Focus();
            }
            else if (e.Key == Key.Escape)
            {
                e.Handled = true;
                CommandList.Visibility = System.Windows.Visibility.Collapsed;
                ConsoleIn.Focus();
            }
        }

        private void CommandList_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Up)
            {
                e.Handled = true;
                if (CommandList.SelectedIndex > 0)  CommandList.SelectedIndex--;
            }

            if (e.Key == Key.Down)
            {
                e.Handled = true;
                if (CommandList.SelectedIndex < CommandList.Items.Count)
                {
                    CommandList.SelectedIndex++;
                }
                else
                {
                    ConsoleIn.Focus();
                }
            }
        }
    }
}
